Skip to content

Implement RFC 640 #23162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 12, 2015
Merged

Implement RFC 640 #23162

merged 6 commits into from
Mar 12, 2015

Conversation

sfackler
Copy link
Member

@sfackler sfackler commented Mar 8, 2015

I've made some minor changes from the implementation attached to the RFC to try to minimize codegen. The methods now take &Debug trait objects rather than being parameterized and there are inlined stub methods that call to non-inlined methods to do the work.

r? @alexcrichton

cc @huonw for the derive(Debug) changes.

@brson
Copy link
Contributor

brson commented Mar 8, 2015

@alexcrichton
Copy link
Member

I'll take a closer look at this tomorrow, but I'm curious why you applied #[inline] attributes at all? It looks like none of these methods require inlining (e.g. none have type parameters) and if you avoid the #[inline] attribute entirely then they'll all just naturally not be inlined because they're across the crate boundary.

@sfackler
Copy link
Member Author

sfackler commented Mar 8, 2015

The public API takes self by value so that we can return the fmt::Result at the call to finish. But if we didn't inline it at all there'd be overhead from repeatedly copying the builder struct around. The current setup has inlineable stub functions that take self by value and do nothing but call a private non-inlineable method that takes &mut self and then returns self. The idea is that the end result is as if the API took &mut self at the assembly level while behaving as if it takes self.

@alexcrichton
Copy link
Member

But if we didn't inline it at all there'd be overhead from repeatedly copying the builder struct around.

Ah ok. If we're trying to minimize codegen though I would probably recommend a &mut self-based builder as it would involve far fewer moves. The finish method could replace the inner result with Ok(()), for example, so it doesn't necessarily have to consume.

In general I'm not so sure about the application of #[inline] throughout these methods. I would be much more convinced with some data though! Without some statistics in favor of the #[inline], I think I'd personally prefer they'd all be removed for now. One interesting statistic would be the before/after size of librustdoc. I know that the lib has probably hundreds of #[derive(Debug)] and if this cuts down on codegen it should really help that size.

Otherwise, my only other concern is the usage in #[derive]. I'm a little unsure about how we lint stability in #[derive]-based implementations, but I just wanted to confirm that this does not require the core feature gate? I personally don't necessarily like the compiler being able to call unstable internals (e.g. the expanded AST won't actually compiled b/c it calls unstable code) where other code cannot, but it's also something we're at liberty to change so I'd be fine giving this a whirl to see what happens!

@sfackler
Copy link
Member Author

I will collect some statistics.

The deriving implementation uses the functionality @huonw added to be able to call unstable APIs without triggering feature gates.

@alexcrichton
Copy link
Member

Ah excellent. cc @huonw on the #[derive] changes then, but I think they're all pretty ok

// the internal fields we're actually formatting
let mut exprs = Vec::new();
// We want to make sure we have the expn_id set so that we can use unstable methods
let span = Span { expn_id: cx.backtrace(), .. span };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you find that this was necessary? I'm under the impression that the macro infrastructure manages re-spanning everything after a macro expansion?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It did not appear to respan - I think only the macro_rules! infrastructure may do that.

@huonw
Copy link
Member

huonw commented Mar 10, 2015

Looks great. Is it worth putting these under a different feature gate to core?

sfackler added 4 commits March 9, 2015 23:24
Switching from generic bounds to trait objects and having un-inlined
inner methods should cut down on the size of Debug impls, since we care
about the speed of a Debug implementation way less than binary bloat.
Turns out it's basically a wash, codegen wise.
@sfackler
Copy link
Member Author

So it turns out that no-inline silliness actually ends up a tiny bit smaller than inline silliness: https://gist.github.com/sfackler/a9300bce13ad166cd35b. Looks like the builder structs are small enough that the copies don't matter.

I pushed a commit that cuts out all the inline annotations.

@sfackler
Copy link
Member Author

Oh, and there doesn't appear to be much of a difference one way or another for overall binary sizes before and after the derive(Debug) change.

@alexcrichton
Copy link
Member

So it turns out that no-inline silliness actually ends up a tiny bit smaller than inline silliness

Thanks for investigating!

Oh, and there doesn't appear to be much of a difference one way or another for overall binary sizes before and after the derive(Debug) change.

Ah well, it probably at least paves the way in the future for such changes though.

@alexcrichton
Copy link
Member

This looks great to me! r=me with a feature name that's not core (e.g. debug_builders or something like that)

@sfackler
Copy link
Member Author

@bors r=alexcrichton 905a611

@bors
Copy link
Collaborator

bors commented Mar 12, 2015

⌛ Testing commit 905a611 with merge eef7330...

bors added a commit that referenced this pull request Mar 12, 2015
I've made some minor changes from the implementation attached to the RFC to try to minimize codegen. The methods now take `&Debug` trait objects rather than being parameterized and there are inlined stub methods that call to non-inlined methods to do the work.

r? @alexcrichton 

cc @huonw for the `derive(Debug)` changes.
@bors
Copy link
Collaborator

bors commented Mar 12, 2015

💔 Test failed - auto-linux-32-nopt-t

@sfackler
Copy link
Member Author

@bors retry

Seems like a spurious error??

@bors
Copy link
Collaborator

bors commented Mar 12, 2015

@bors
Copy link
Collaborator

bors commented Mar 12, 2015

⛄ The build was interrupted to prioritize another pull request.

@bors
Copy link
Collaborator

bors commented Mar 12, 2015

@bors
Copy link
Collaborator

bors commented Mar 12, 2015

⛄ The build was interrupted to prioritize another pull request.

bors added a commit that referenced this pull request Mar 12, 2015
I've made some minor changes from the implementation attached to the RFC to try to minimize codegen. The methods now take `&Debug` trait objects rather than being parameterized and there are inlined stub methods that call to non-inlined methods to do the work.

r? @alexcrichton 

cc @huonw for the `derive(Debug)` changes.
@bors
Copy link
Collaborator

bors commented Mar 12, 2015

⌛ Testing commit 905a611 with merge 49f7550...

@bors bors merged commit 905a611 into rust-lang:master Mar 12, 2015
@SimonSapin SimonSapin mentioned this pull request Apr 2, 2015
@SimonSapin
Copy link
Contributor

Should assert_eq! default to using this? (I just found out about this, it looks great!)

@liigo
Copy link
Contributor

liigo commented Jul 8, 2015

keywords: pretty debug builders
rfc: rust-lang/rfcs#640
(to help people finding this rfc implementation)

@sunjay
Copy link
Member

sunjay commented Jun 4, 2016

@SimonSapin It would be great is assert_eq! used this. I don't know what a good way to integrate it in my tests right now without that.

@sfackler sfackler deleted the debug-builders branch June 4, 2016 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants